import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { RedisService } from "./redis.service";
import { CharacterLocationEntity } from "../entities/character-location.entity";
import { MapAreaService } from "./map-area.service";

@Injectable()
export class CharacterLocationService {
  private readonly logger = new Logger(CharacterLocationService.name);

  constructor(
    @InjectRepository(CharacterLocationEntity)
    private locationRepo: Repository<CharacterLocationEntity>,
    private redisService: RedisService,
    private mapAreaService: MapAreaService
  ) { }

  /**
   * 创建角色默认位置
   */
  async createDefaultLocation(
    characterId: number
  ): Promise<CharacterLocationEntity> {
    const defaultLocation = this.locationRepo.create({
      characterId,
      areaId: 2, // 默认新手村
      lastMoveTime: new Date(),
      isOnline: 1,
      lastOnlineTime: new Date(),
    });

    const savedLocation = await this.locationRepo.save(defaultLocation);

    // 同步更新Redis缓存
    await this.updateRedisLocationCache(characterId, savedLocation);
    await this.addPlayerToAreaCache(2, characterId);
    await this.updateOnlinePlayerInAreaCache(2, characterId, savedLocation);

    return savedLocation;
  }

  /**
   * 更新玩家位置
   */
  async updatePlayerLocation(
    characterId: number,
    newAreaId: number
  ): Promise<void> {
    try {
      // 获取当前位置
      const currentLocation = await this.locationRepo.findOne({
        where: { characterId },
        relations: ["character", "area"],
      });

      if (!currentLocation) {
        throw new Error(`角色位置记录不存在: ${characterId}`);
      }

      const oldAreaId = currentLocation.areaId;
      console.log(
        `🔄 开始更新玩家 ${characterId} 位置: ${oldAreaId} -> ${newAreaId}`
      );

      // 使用QueryBuilder进行更新，确保数据被正确保存
      const updateResult = await this.locationRepo
        .createQueryBuilder()
        .update(CharacterLocationEntity)
        .set({
          areaId: newAreaId,
          lastMoveTime: new Date(),
          lastOnlineTime: new Date(),
        })
        .where("characterId = :characterId", { characterId })
        .execute();

      console.log(`📊 数据库更新结果:`, updateResult);

      // 验证更新是否成功
      if (updateResult.affected === 0) {
        throw new Error(`数据库更新失败，没有记录被修改: ${characterId}`);
      }

      // 重新查询更新后的数据
      const updatedLocation = await this.locationRepo.findOne({
        where: { characterId },
        relations: ["character", "area"],
      });

      if (!updatedLocation) {
        throw new Error(`无法获取更新后的位置信息: ${characterId}`);
      }

      console.log(
        `💾 玩家 ${characterId} 位置已保存到数据库: 区域 ${oldAreaId} -> ${updatedLocation.areaId}`
      );

      // 同步更新Redis缓存
      await this.updateRedisLocationCache(characterId, updatedLocation);

      // 从旧区域移除
      await this.removePlayerFromAreaCache(oldAreaId, characterId);
      await this.removeOnlinePlayerFromAreaCache(oldAreaId, characterId);

      // 添加到新区域
      await this.addPlayerToAreaCache(newAreaId, characterId);
      if (updatedLocation.isOnline === 1) {
        await this.updateOnlinePlayerInAreaCache(
          newAreaId,
          characterId,
          updatedLocation
        );
      }

      // 确保缓存中的角色信息是最新的（包括等级等）
      await this.updatePlayerCharacterInfo(characterId);

      console.log(
        `✅ 玩家 ${characterId} 位置更新完成: ${oldAreaId} -> ${updatedLocation.areaId}`
      );
    } catch (error) {
      console.error(
        `❌ 更新玩家位置失败: characterId=${characterId}, newAreaId=${newAreaId}`,
        error
      );
      throw error;
    }
  }

  /**
   * 获取区域内的在线玩家列表
   */
  async getOnlinePlayersInArea(areaId: number): Promise<any[]> {
    // 优先从Redis获取在线玩家信息
    const redisKey = `online_players:area:${areaId}`;
    const players = await this.redisService.hgetall(redisKey);

    if (Object.keys(players).length > 0) {
      return Object.values(players).map((player) => JSON.parse(player));
    }

    // Redis没有数据，从数据库获取并同步到Redis
    const locations = await this.locationRepo.find({
      where: { areaId, isOnline: 1 },
      relations: ["character", "area"],
    });

    const playerList = locations.map((location) => ({
      characterId: location.characterId,
      characterName: location.character?.name || "未知玩家",
      areaId: location.areaId,
      areaName: location.area?.name || "未知区域",
      lastMoveTime: location.lastMoveTime,
      isOnline: location.isOnline,
      // 添加角色详细信息用于格式化
      character: {
        lvl: location.character?.lvl || 1,
        sex: location.character?.sex || 1,
        roleType: location.character?.roleType || 1,
      },
    }));

    // 将所有在线玩家信息同步到Redis缓存
    for (const player of playerList) {
      await this.redisService.hset(
        redisKey,
        player.characterId.toString(),
        JSON.stringify(player)
      );
    }

    // 设置过期时间（1小时）
    await this.redisService.expire(redisKey, 3600);

    return playerList;
  }

  /**
   * 更新缓存中的角色信息（用于角色等级变化时）
   */
  async updatePlayerCharacterInfo(characterId: number): Promise<void> {
    try {
      // 从数据库获取最新的角色信息
      const location = await this.locationRepo.findOne({
        where: { characterId },
        relations: ["character", "area"],
      });

      if (!location) {
        this.logger.warn(`角色位置信息不存在: ${characterId}，尝试创建默认位置`);
        // 如果位置信息不存在，创建默认位置
        await this.createDefaultLocation(characterId);
        return;
      }

      // 更新Redis中的位置缓存
      await this.updateRedisLocationCache(characterId, location);

      // 更新区域缓存中的角色信息
      const redisKey = `online_players:area:${location.areaId}`;
      const playerData = {
        characterId: location.characterId,
        characterName: location.character?.name || "未知玩家",
        areaId: location.areaId,
        areaName: location.area?.name || "未知区域",
        lastMoveTime: location.lastMoveTime,
        isOnline: location.isOnline,
        character: {
          lvl: location.character?.lvl || 1,
          sex: location.character?.sex || 1,
          roleType: location.character?.roleType || 1,
        },
      };

      // 更新Redis中的在线玩家信息
      await this.redisService.hset(
        redisKey,
        characterId.toString(),
        JSON.stringify(playerData)
      );

      this.logger.log(
        `角色信息缓存已更新: ${characterId}, 等级: ${location.character?.lvl || 1}`
      );
    } catch (error) {
      this.logger.error(
        `更新角色信息缓存失败: characterId=${characterId}`,
        error
      );
    }
  }

  /**
   * 设置玩家在线状态
   */
  async setPlayerOnlineStatus(
    characterId: number,
    isOnline: boolean
  ): Promise<void> {
    const location = await this.locationRepo.findOne({
      where: { characterId },
      relations: ["character", "area"],
    });

    if (location) {
      location.isOnline = isOnline ? 1 : 0;
      location.lastOnlineTime = new Date();

      if (isOnline) {
        location.lastMoveTime = new Date();
      }

      await this.locationRepo.save(location);

      // 同步更新Redis缓存
      await this.updateRedisLocationCache(characterId, location);

      if (isOnline) {
        // 玩家上线：添加到区域在线玩家列表
        await this.addPlayerToAreaCache(location.areaId, characterId);
        await this.updateOnlinePlayerInAreaCache(
          location.areaId,
          characterId,
          location
        );
      } else {
        // 玩家下线：从区域在线玩家列表移除
        await this.removePlayerFromAreaCache(location.areaId, characterId);
        await this.removeOnlinePlayerFromAreaCache(
          location.areaId,
          characterId
        );
      }
    }
  }

  /**
   * 玩家下线处理（WebSocket连接断开时调用）
   */
  async handlePlayerOffline(characterId: number): Promise<void> {
    try {
      // 获取玩家当前位置
      const location = await this.getPlayerLocation(characterId);

      if (location && location.isOnline === 1) {
        // 从Redis中移除玩家在线状态
        await this.removeOnlinePlayerFromAreaCache(
          location.areaId,
          characterId
        );
        await this.removePlayerFromAreaCache(location.areaId, characterId);

        // 更新数据库中的在线状态
        await this.setPlayerOnlineStatus(characterId, false);

        console.log(
          `✅ 玩家 ${characterId} 已从区域 ${location.areaId} 在线玩家列表中移除`
        );
      }
    } catch (error) {
      console.error(`❌ 处理玩家下线失败: characterId=${characterId}`, error);
    }
  }

  /**
   * 清理离线玩家的位置缓存
   */
  async cleanupOfflinePlayers(): Promise<void> {
    try {
      const offlineThreshold = new Date(Date.now() - 30 * 60 * 1000); // 30分钟

      // 使用TypeORM的QueryBuilder来构建复杂的日期比较查询
      const offlineLocations = await this.locationRepo
        .createQueryBuilder("location")
        .where("location.isOnline = :isOnline", { isOnline: 0 })
        .andWhere("location.lastOnlineTime < :threshold", {
          threshold: offlineThreshold,
        })
        .getMany();

      console.log(`🔍 发现 ${offlineLocations.length} 个离线玩家需要清理缓存`);

      for (const location of offlineLocations) {
        try {
          // 清理Redis缓存
          await this.removePlayerFromAreaCache(
            location.areaId,
            location.characterId
          );
          await this.removeOnlinePlayerFromAreaCache(
            location.areaId,
            location.characterId
          );
          await this.redisService.del(
            `player_location:${location.characterId}`
          );

          console.log(`✅ 已清理玩家 ${location.characterId} 的缓存`);
        } catch (error) {
          console.error(`❌ 清理玩家 ${location.characterId} 缓存失败:`, error);
        }
      }

      console.log(
        `🎉 离线玩家缓存清理完成，共处理 ${offlineLocations.length} 个玩家`
      );
    } catch (error) {
      console.error("❌ 离线玩家缓存清理失败:", error);
    }
  }

  /**
   * 获取玩家当前位置
   */
  async getPlayerLocation(
    characterId: number
  ): Promise<CharacterLocationEntity | null> {
    // 先从Redis获取
    const redisKey = `player_location:${characterId}`;
    const cachedLocation = await this.redisService.get(redisKey);

    if (cachedLocation) {
      try {
        // 解析缓存的JSON数据
        const parsedLocation = JSON.parse(cachedLocation);

        // 验证缓存数据的完整性
        if (
          parsedLocation &&
          typeof parsedLocation === "object" &&
          parsedLocation.characterId
        ) {
          console.log(`📋 从Redis缓存获取玩家 ${characterId} 位置信息`);
          return parsedLocation as any;
        } else {
          console.warn(
            `⚠️ Redis缓存数据格式错误，删除无效缓存: ${characterId}`
          );
          await this.redisService.del(redisKey);
        }
      } catch (error) {
        console.error(`❌ 解析Redis缓存数据失败: ${characterId}`, error);
        // 删除损坏的缓存
        await this.redisService.del(redisKey);
      }
    }

    // Redis没有数据或数据无效，从数据库获取
    const location = await this.locationRepo.findOne({
      where: { characterId },
      relations: ["character", "area"],
    });

    if (location) {
      // 更新Redis缓存
      await this.updateRedisLocationCache(characterId, location);
    }

    return location;
  }

  /**
   * 验证目标位置是否存在
   */
  async validateTargetArea(areaId: number): Promise<boolean> {
    try {
      const area = await this.mapAreaService.getAreaById(areaId);
      return !!area;
    } catch (error) {
      return false;
    }
  }

  // 私有方法：Redis缓存操作
  private async updateRedisLocationCache(
    characterId: number,
    location: CharacterLocationEntity
  ): Promise<void> {
    const redisKey = `player_location:${characterId}`;
    const locationData = {
      ...location,
      areaName: location.area?.name || "未知区域",
    };

    await this.redisService.set(redisKey, JSON.stringify(locationData), 3600); // 1小时过期
  }

  private async addPlayerToAreaCache(
    areaId: number,
    characterId: number
  ): Promise<void> {
    const redisKey = `area_players:${areaId}`;
    const score = Date.now();
    await this.redisService.zadd(redisKey, score, characterId.toString());
    await this.redisService.expire(redisKey, 3600); // 1小时过期
  }

  private async removePlayerFromAreaCache(
    areaId: number,
    characterId: number
  ): Promise<void> {
    const redisKey = `area_players:${areaId}`;
    await this.redisService.zrem(redisKey, characterId.toString());
  }

  /**
   * 更新区域在线玩家缓存
   */
  private async updateOnlinePlayerInAreaCache(
    areaId: number,
    characterId: number,
    location: CharacterLocationEntity
  ): Promise<void> {
    const redisKey = `online_players:area:${areaId}`;
    const playerData = {
      characterId: location.characterId,
      characterName: location.character?.name || "未知玩家",
      areaId: location.areaId,
      areaName: location.area?.name || "未知区域",
      lastMoveTime: location.lastMoveTime,
      isOnline: location.isOnline,
      // 添加角色详细信息用于格式化（717指令需要）
      character: {
        lvl: location.character?.lvl || 1,
        sex: location.character?.sex || 1,
        roleType: location.character?.roleType || 1,
      },
    };

    await this.redisService.hset(
      redisKey,
      characterId.toString(),
      JSON.stringify(playerData)
    );
    await this.redisService.expire(redisKey, 3600); // 1小时过期
  }

  /**
   * 从区域在线玩家缓存中移除
   */
  private async removeOnlinePlayerFromAreaCache(
    areaId: number,
    characterId: number
  ): Promise<void> {
    const redisKey = `online_players:area:${areaId}`;
    await this.redisService.hdel(redisKey, characterId.toString());
  }
}
